package org.example.gateway.filters;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.example.common.core.constants.Constants;
import org.example.gateway.config.properties.IgnoreWhiteProperties;
import org.example.gateway.utils.WebFluxUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.PathContainer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务内部与外部分离
 */
@Component
public class GlobalAuthenticationFilter implements GlobalFilter, Ordered {

    private Logger log= LoggerFactory.getLogger(GlobalAuthenticationFilter.class);

    @Autowired
    private TokenStore tokenStore;
    @Autowired
    private IgnoreWhiteProperties ignoreWhiteProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestUrl = exchange.getRequest().getPath().value();
        //1、白名单放行，比如授权服务、静态资源…………
        if (ignoreWhiteProperties.checkUrls(requestUrl)){
            return chain.filter(exchange);
        }
        //2、 检查token是否存在
        String token = getToken(exchange);
        if (StringUtils.isBlank(token))
            return invalidTokenMono(exchange,401,"请求非法");
        //3 判断是否是有效的token
        OAuth2AccessToken oAuth2AccessToken;
        try {
            //解析token.使用token
             oAuth2AccessToken=tokenStore.readAccessToken(token);
             Map<String, Object> additionalInformation = oAuth2AccessToken.getAdditionalInformation();
            //取出用户身份信息
            additionalInformation.put(Constants.EXPIRES_IN,oAuth2AccessToken.getExpiration());
            //将解析后的token加密放入请求头中,方便下游微服务解析获取用户信息
            String base64 = Base64.encode(JSON.toJSONString(additionalInformation));
            // 设置用户信息到请求
            ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(Constants.AUTHORIZATION_TOKEN_HEADER, base64).build();
            ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
            return chain.filter(mutableExchange);
         }catch (InvalidTokenException e){
               return invalidTokenMono(exchange,401,"令牌无效");
        }

    }



    private Mono<Void> invalidTokenMono(ServerWebExchange exchange,Integer code,String msg)
    {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        Map result=new HashMap();
        result.put("code",code);
        result.put("msg",msg);
        return WebFluxUtils.webFluxResponseWriter(response,result);
//        return response.writeWith(Mono.fromSupplier(() -> {
//            Map result=new HashMap();
//            result.put("code",code);
//            result.put("msg",msg);
//            DataBufferFactory bufferFactory = response.bufferFactory();
//            return bufferFactory.wrap(JSON.toJSONBytes(result));
//        }));
    }


    /**
     * 获取请求token
     */
    private String getToken(ServerWebExchange exchange)
    {
        ServerHttpRequest request=exchange.getRequest();
        String token = request.getHeaders().getFirst(Constants.HEADER);
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
        {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

    private boolean checkUrls(List<String> urls,String pathUrl){
        if(ObjectUtil.isNotEmpty(urls)&&urls.size()>0){
            return urls.stream().anyMatch(url->{
                PathPattern pathPattern = PathPatternParser.defaultInstance.parse(url);
                PathContainer pathContainer = PathContainer.parsePath(pathUrl);
                return pathPattern.matches(pathContainer);
            });
        }

        return false;
    }
    @Override
    public int getOrder() {
        return 0;
    }
}
